package person.twj.jwt.core.security;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import person.twj.jwt.core.security.constant.TokenConstants;
import person.twj.jwt.core.security.handler.ErrorHandler;
import person.twj.jwt.core.security.handler.MyNotLoginAccessHandler;
import person.twj.jwt.core.security.handler.MyUsernamePasswordAuthenticationFilter;
import person.twj.jwt.core.security.handler.TokenVerifyFilter;
import person.twj.jwt.core.security.service.MyUserDetailsService;

import static org.springframework.security.config.Customizer.withDefaults;

@Configuration
//@EnableWebSecurity // 开启springSecurity自定义配置，在springboot项目中，可以省略该注解，因为它自动引入了该注解
public class WebSecurityConfig {
	@Bean
	public  PasswordEncoder passwordEncoder( ){
		return  new BCryptPasswordEncoder();
	}


	@Bean
	public UserDetailsService userDetailsService() {
		return new MyUserDetailsService();
	}


	@Bean
	public SecurityFilterChain filterChain(HttpSecurity http, AuthenticationConfiguration authenticationConfiguration) throws Exception {
		http.authorizeHttpRequests(
				authorize -> authorize
						// 禁止使用 /**
						// 放开不用认证的请求 AbstractAuthenticationProcessingFilter

						.requestMatchers(TokenConstants.TOKEN_URL).permitAll()
						.requestMatchers(TokenConstants.REFRESH_TOKEN_URL).permitAll()
						.requestMatchers("/error").permitAll()
						.anyRequest()
						//已认证的请求会被自动授权
						.authenticated()



				);
		http.sessionManagement(sessionManagementCustomizer -> {
//					用户登录成功后，信息保存在服务器Session中。SpringSecurity提供了4种方式控制会话创建。
//					* always：如果一个会话尚不存在，将始终创建一个会话。
//					* ifRequired：仅在需要时创建会话，默认。
//					* never：框架永远不会创建会话本身，但如果它已经存在，它将使用一个。
//					* stateless：不会创建或使用任何会话，完全无状态。

			// 因为使用jwt，所以禁用session
			sessionManagementCustomizer.sessionCreationPolicy(SessionCreationPolicy.STATELESS);

		});

		http.httpBasic(basic -> basic.disable());
		http.formLogin((formLogin) ->formLogin.disable());

		http.logout(logout->logout.disable());


//		http.addFilterBefore(new ErrorHandler(), UsernamePasswordAuthenticationFilter.class);
		http.addFilterBefore(new TokenVerifyFilter(), UsernamePasswordAuthenticationFilter.class);
		http.addFilterAt(
				new MyUsernamePasswordAuthenticationFilter(
					TokenConstants.TOKEN_URL,
					authenticationConfiguration.getAuthenticationManager()
				),
				UsernamePasswordAuthenticationFilter.class);

		http.exceptionHandling(exception -> {
			// 未登录返回
			exception.authenticationEntryPoint(new MyNotLoginAccessHandler());
		});

		// 关闭”crsf攻击“防御 ,登录时会带参数_crsf
		http.csrf(csrf -> csrf.disable());

		// 开启跨域访问限制
//		http.cors(cors->cors.disable());
		http.cors(withDefaults());


		return http.build();

	}
}